package hms.employees;


import hms.database.DBRowObject;

import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Date;
import java.util.Calendar;
import java.util.GregorianCalendar;

/**
 * Employee holds Employee name, hire/fire dates, title, and reason for firing.
 * 
 * @author Ben
 *
 */
/**
 * @author Ben
 *
 */
public class Employee extends DBRowObject {

	// Name
	private String firstName;
	private String lastName;
	// Dates hired/fired
	private Calendar hireDate;
	private Calendar terminationDate;
	// Currently fired
	private boolean terminated;
	// Reason for firing
	private TerminationReason terminationReason;
	// Job title
	private JobTitle position;
	
	/**
	 * Create an new employee object. 
	 */
	public Employee() {
		super();
		firstName = "?";
		lastName = "?";
		hireDate = GregorianCalendar.getInstance();
		//hireDate.set(2012,01,01);
		terminationDate = GregorianCalendar.getInstance();
		//terminationDate.set(2012,01,01);
		terminated = false;
		terminationReason = new TerminationReason("Employed");
		position = new JobTitle();
	}
	
	/**
	 * Load an employee from the database using primary key uniqueID.
	 * 
	 * @param uniqueID
	 */
	public Employee(int uniqueID) {
		super(uniqueID);
	}
	
	/**
	 * Get the first name
	 * 
	 * @return the firstName
	 */
	public String getFirstName() {
		return firstName;
	}

	/**
	 * Set the first name, and mark object as different than DB copy. The name
	 * must only contain letters, numbers, and spaces.
	 * <p>
	 * Changing the first name internally marks the employee record as being
	 * significant- i.e. it will not be deleted if it belongs to a UserAccount
	 * and is replaced.
	 * <b>Postcondition:</b> Object is marked as changed from DB copy
	 * 
	 * @param firstName
	 *            the firstName to set
	 */
	public void setFirstName(String firstName) {
		this.firstName = reduceCharset(firstName);
		markAsChanged();
	}

	/**
	 * Get the last name
	 * 
	 * @return the lastName
	 */
	public String getLastName() {
		return lastName;
	}

	/**
	 * Set the last name, and mark object as different than DB copy. The name
	 * must only contain letters, numbers, and spaces.
	 * <p>
	 * <b>Postcondition:</b> Object is marked as changed from DB copy
	 * 
	 * @param lastName the lastName to set
	 */
	public void setLastName(String lastName) {
		this.lastName = reduceCharset(lastName);
		markAsChanged();
	}

	/**
	 * Returns first and last name separated by space, in that order.
	 * 
	 * @return
	 */
	public String getFullName() {
		return getFirstName() + " " + getLastName();
	}
	
	
	/**
	 * Calls setFirstName and setLastName together, for convenience.
	 * 
	 * @see #setFirstName(String)
	 * @see #setLastName(String)
	 * 
	 * @param firstname
	 * @param lastname
	 */
	public void setFullname(String firstname, String lastname) {
		setFirstName(firstname);
		setLastName(lastname);
	}
	
	/**
	 * Return employee's name, employment status and position (hired) or reason
	 * for termination (fired).
	 * 
	 * @see java.lang.Object#toString()
	 */
	public String toString() {
		if(terminated) {
			return getFullName() + ", Fired " + getFireYear() + "-" + getFireMonth() + "-" + getFireDay() + ", Reason: " + terminationReason.getTerminationReasonString();	
		} else {
			return getFullName() + ", Hired " + getHireYear() + "-" + getHireMonth() + "-" + getHireDay() + ", Position: " + position.getJobTitle();
		}
	}
	
	/**
	 * Return the job position as a string
	 * 
	 * @return the position
	 */
	public String getPosition() {
		return position.getJobTitle();
	}

	/**
	 * Change the person's job title
	 * <p>
	 * <b>Postcondition:</b> Object is marked as changed from DB copy
	 * 
	 * @param position the position to set
	 */
	public void setPosition(String position) {
		this.position = new JobTitle(position);
		markAsChanged();
	}
	
	
	/**
	 * Get the year of hire as an integer.
	 * 
	 * @return integer representing year of hire.
	 */
	public int getHireYear() {
		return hireDate.get(Calendar.YEAR);
	}
	
	/**
	 * Get the month of hire.
	 * 
	 * @return integer representing month of hire.
	 */
	public int getHireMonth() {
		return hireDate.get(Calendar.MONTH)+1;
	}
	
	/**
	 * Get the day of hire.
	 * 
	 * @return integer representing day of the month of hire.
	 */
	public int getHireDay() {
		return hireDate.get(Calendar.DAY_OF_MONTH);
	}
	
	/**
	 * Get the year of termination.
	 * 
	 * @return integer representing year of termination. 
	 */
	public int getFireYear() {
		return terminationDate.get(Calendar.YEAR);
	}
	
	/**
	 * Get the month of termination.
	 * 
	 * @return integer representing month of termination. 
	 */
	public int getFireMonth() {
		return terminationDate.get(Calendar.MONTH);
	}
	
	/**
	 * Get the day of the month of termination.
	 * 
	 * @return integer representing day of termination.
	 */
	public int getFireDay() {
		return terminationDate.get(Calendar.DAY_OF_MONTH);
	}

	/**
	 * Set the date of hire of the employee.
	 * <p>
	 * <b>Postcondition:</b> Object is marked as changed from DB copy
	 * 
	 * @param year Year of hire
	 * @param month Month of hire
	 * @param day Day of the month of hire
	 */
	public void setHireDate(int year, int month, int day) {
		this.hireDate.set(year, month-1, day);
		markAsChanged();
	}

	/**
	 * Set the date of termination of the employee.
	 * <p>
	 * <b>Postcondition:</b> Object is marked as changed from DB copy
	 * 
	 * @param year Year of termination
	 * @param month Month of termination
	 * @param day Day of the month of termination
	 */
	public void setTerminationDate(int year, int month, int day) {
		this.terminationDate.set(year, month, day);
		markAsChanged();
	}

	/**
	 * Return true if employee has been terminated, false otherwise.
	 * 
	 * @return True if terminated, false otherwise.
	 */
	public Boolean isTerminated() {
		return terminated;
	}

	/**
	 * Set whether the employee has been terminated or not.
	 * <p>
	 * <b>Postcondition:</b> If the employee is not fired, the termination reason will be reset to "Employed".
	 * 
	 * @param terminated
	 */
	public void setTerminated(Boolean terminated) {
		this.terminated = terminated;
		if(!terminated) {
			this.terminationReason = new TerminationReason("Employed");
		}
		markAsChanged();
	}

	/**
	 * Retrieve the reason for termination. If the user is currently not fired,
	 * then this function will return "Employed".
	 * 
	 * @return String with termination reason.
	 */
	public String getTerminationReason() {
		return terminationReason.getTerminationReasonString();
	}

	/**
	 * Set the reason for terminating this employee. If the reason is not
	 * "Employed", then the employee will also be marked as terminated.
	 * <p>
	 * <b>Postcondition:</b> If the employee's termination reason is not
	 * "Employed", then the terminated flag will be set.
	 * 
	 * @param terminationReason
	 *            the terminationReason to set
	 */
	public void setTerminationReason(String terminationReason) {
		this.terminationReason = new TerminationReason(terminationReason);
		//this.terminated = !(terminationReason.equals("Employed"));
		markAsChanged();
	}
	
	/**
	 * Returns whether the first name field has been changed from the default.
	 * 
	 * @return 
	 */
	public boolean isDefault() {
		return firstName.equals("?");
	}
	
	@Override
	protected String[] getFieldNames() {
		String[] out = new String[6];
		out[0] = "FIRSTNAME";
		out[1] = "LASTNAME";
		out[2] = "HIREDATE";
		out[3] = "FIREDATE";
		out[4] = "FIREREASON_ID";
		out[5] = "JOBTITLE_ID";
		return out;
	}

	@Override
	protected void loadPreparedStatement(PreparedStatement stmt)
			throws SQLException {
		stmt.setString(1, firstName);
		stmt.setString(2, lastName);
		stmt.setDate(3, new Date(hireDate.getTimeInMillis()));
		stmt.setDate(4, new Date(terminationDate.getTimeInMillis()));
		if(!terminated) {
			terminationReason = new TerminationReason("Employed");
		}
		terminationReason.commitToDatabase();
		stmt.setInt(5, terminationReason.getUniqueIdentifier());
		position.commitToDatabase();
		stmt.setInt(6, position.getUniqueIdentifier());
	}

	@Override
	protected String getUniqueIdentifierFieldName() {
		return "EMPLOYEE_ID";
	}

	@Override
	protected String getTableName() {
		// TODO Auto-generated method stub
		return "EMPLOYEE";
	}

	@Override
	protected void loadFromDatabase(ResultSet rs) throws SQLException {
		firstName = rs.getString("FIRSTNAME");
		lastName = rs.getString("LASTNAME");
		hireDate = GregorianCalendar.getInstance();
		hireDate.setTimeInMillis(rs.getDate("HIREDATE").getTime());
		terminationDate = GregorianCalendar.getInstance();
		terminationDate.setTimeInMillis(rs.getDate("FIREDATE").getTime());
		terminationReason = new TerminationReason(rs.getInt("FIREREASON_ID"));
		terminated = !(terminationReason.getTerminationReasonString().equals("Employed"));
		position = new JobTitle(rs.getInt("JOBTITLE_ID"));
	}

	@Override
	protected boolean allowDuplicateRows() {
		return true;
	}
	
}
